home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / SwingUtilities.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  56.9 KB  |  1,586 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)SwingUtilities.java    1.70 98/08/26
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package javax.swing;
  15.  
  16. import java.applet.*;
  17.  
  18. import java.awt.*;
  19. import java.awt.event.*;
  20.  
  21. import java.util.Vector;
  22. import java.util.Hashtable;
  23.  
  24. import java.lang.reflect.*;
  25.  
  26. import javax.accessibility.*;
  27.  
  28.  
  29. /**
  30.  * A collection of utility methods for Swing.
  31.  *
  32.  * @version 1.70 08/26/98
  33.  * @author unknown
  34.  */
  35. public class SwingUtilities implements SwingConstants
  36. {
  37.     // These states are system-wide, rather than AppContext wide.
  38.     private static boolean canAccessEventQueue = false;
  39.     private static boolean eventQueueTested = false;
  40.  
  41.  
  42.     /** 
  43.      * Return true if <code>a</code> contains <code>b</code>
  44.      */
  45.     public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) {
  46.         if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width) &&
  47.             b.y >= a.y && (b.y + b.height) <= (a.y + a.height)) {
  48.             return true;
  49.         }
  50.         return false;
  51.     }
  52.  
  53.     /**
  54.      * Return the rectangle (0,0,bounds.width,bounds.height) for the component <code>aComponent</code>
  55.      */
  56.     public static Rectangle getLocalBounds(Component aComponent) {
  57.         Rectangle b = new Rectangle(aComponent.getBounds());
  58.         b.x = b.y = 0;
  59.         return b;
  60.     }
  61.  
  62.  
  63.     /**
  64.      * @return the first Window ancestor of c
  65.      */
  66.     private static Window getWindowAncestor(Component c) {
  67.         for(Container p = c.getParent(); p != null; p = p.getParent()) {
  68.             if (p instanceof Window) {
  69.                 return (Window)p;
  70.             }
  71.         }
  72.         return null;
  73.     }
  74.  
  75.  
  76.     /**
  77.      * Convert a <code>aPoint</code> in <code>source</code> coordinate system to
  78.      * <code>destination</code> coordinate system.
  79.      * If <code>source></code>is null,<code>aPoint</code> is assumed to be in <code>destination</code>'s
  80.      * root component coordinate system.
  81.      * If <code>destination</code>is null, <code>aPoint</code> will be converted to <code>source</code>'s
  82.      * root component coordinate system.
  83.      * If both <code>source</code> and <code>destination</code> are null, return <code>aPoint</code>
  84.      * without any conversion.
  85.      */
  86.     public static Point convertPoint(Component source,Point aPoint,Component destination) {
  87.         Point p;
  88.  
  89.         if(source == null && destination == null)
  90.             return aPoint;
  91.         if(source == null) {
  92.             source = getWindowAncestor(destination);
  93.             if(source == null)
  94.                 throw new Error("Source component not connected to component tree hierarchy");
  95.         }
  96.         p = new Point(aPoint);
  97.         convertPointToScreen(p,source);
  98.         if(destination == null) {
  99.             destination = getWindowAncestor(source);
  100.             if(destination == null)
  101.                 throw new Error("Destination component not connected to component tree hierarchy");
  102.         }
  103.         convertPointFromScreen(p,destination);
  104.         return p;
  105.     }
  106.  
  107.     /**
  108.      * Convert the point <code>(x,y)</code> in <code>source</code> coordinate system to
  109.      * <code>destination</code> coordinate system.
  110.      * If <code>source></code>is null,<code>(x,y)</code> is assumed to be in <code>destination</code>'s
  111.      * root component coordinate system.
  112.      * If <code>destination</code>is null, <code>(x,y)</code> will be converted to <code>source</code>'s
  113.      * root component coordinate system.
  114.      * If both <code>source</code> and <code>destination</code> are null, return <code>(x,y)</code>
  115.      * without any conversion.
  116.      */
  117.     public static Point convertPoint(Component source,int x, int y,Component destination) {
  118.         Point point = new Point(x,y);
  119.         return convertPoint(source,point,destination);
  120.     }
  121.  
  122.     /** 
  123.      * Convert the rectangle <code>aRectangle</code> in <code>source</code> coordinate system to
  124.      * <code>destination</code> coordinate system.
  125.      * If <code>source></code>is null,<code>aRectangle</code> is assumed to be in <code>destination</code>'s
  126.      * root component coordinate system.
  127.      * If <code>destination</code>is null, <code>aRectangle</code> will be converted to <code>source</code>'s
  128.      * root component coordinate system.
  129.      * If both <code>source</code> and <code>destination</code> are null, return <code>aRectangle</code>
  130.      * without any conversion.
  131.      */
  132.     public static Rectangle convertRectangle(Component source,Rectangle aRectangle,Component destination) {
  133.         Point point = new Point(aRectangle.x,aRectangle.y);
  134.         point =  convertPoint(source,point,destination);
  135.         return new Rectangle(point.x,point.y,aRectangle.width,aRectangle.height);
  136.     }
  137.  
  138.     /**
  139.      * Convenience method for searching above <code>comp</code> in the
  140.      * component hierarchy and returns the first object of class <code>c</code> it
  141.      * finds. Can return null, if a class <code>c</code> cannot be found.
  142.      */
  143.     public static Container getAncestorOfClass(Class c, Component comp) {
  144.         if(comp == null || c == null)
  145.             return null;
  146.  
  147.         Container parent = comp.getParent();
  148.         while(parent != null && !(c.isInstance(parent)))
  149.             parent = parent.getParent();
  150.         return parent;
  151.     }
  152.  
  153.     /**
  154.      * Convenience method for searching above <code>comp</code> in the
  155.      * component hierarchy and returns the first object of <code>name</code> it
  156.      * finds. Can return null, if <code>name</code> cannot be found.
  157.      */
  158.     public static Container getAncestorNamed(String name, Component comp) {
  159.         if(comp == null || name == null)
  160.             return null;
  161.  
  162.         Container parent = comp.getParent();
  163.         while(parent != null && !(name.equals(parent.getName())))
  164.             parent = parent.getParent();
  165.         return parent;
  166.     }
  167.  
  168.     /**
  169.      * Returns the deepest visible descendent Component of <code>parent</code> 
  170.      * that contains the location <code>x</code>, <code>y</code>. 
  171.      * If <code>parent</code> does not contain the specified location,
  172.      * then <code>null</code> is returned.  If <code>parent</code> is not a 
  173.      * container, or none of <code>parent</code>'s visible descendents 
  174.      * contain the specified location, <code>parent</code> is returned.
  175.      *
  176.      * @param parent the root component to begin the search
  177.      * @param x the x target location 
  178.      * @param y the y target location  
  179.      */
  180.     public static Component getDeepestComponentAt(Component parent, int x, int y) {
  181.         if (!parent.contains(x, y)) {
  182.             return null;
  183.         }
  184.         if (parent instanceof Container) {        
  185.             Component components[] = ((Container)parent).getComponents();
  186.             for (int i = 0 ; i < components.length ; i++) {
  187.                 Component comp = components[i];
  188.                 if (comp != null) {
  189.                     Point loc = comp.getLocation();
  190.                     if (comp instanceof Container) {
  191.                         comp = getDeepestComponentAt(comp, x - loc.x, y - loc.y);
  192.                     } else {
  193.                         comp = comp.getComponentAt(x - loc.x, y - loc.y);
  194.                     }
  195.                     if (comp != null && comp.isVisible()) {
  196.                         return comp;
  197.                     }
  198.                 }
  199.             }
  200.         }
  201.         return parent;
  202.     }
  203.  
  204.  
  205.     /** 
  206.      * Returns a MouseEvent similar to <code>sourceEvent</code> except that its x
  207.      * and y members have been converted to <code>destination</code>'s coordinate
  208.      * system.  If <code>source</code> is null, <code>sourceEvent</code> x and y members
  209.      * are assumed to be into <code>destination<code>'s root component coordinate system.
  210.      * If <code>destination</code> is <code>null</code>, the
  211.      * returned MouseEvent will be in <code>source</code>'s coordinate system.
  212.      * <code>sourceEvent</code> will not be changed. A new event is returned.
  213.      * the <code>source</code> field of the returned event will be set
  214.      * to <code>destination</code> if destination is non null
  215.      * use the translateMouseEvent() method to translate a mouse event from
  216.      * one component to another without changing the source.
  217.      */
  218.     public static MouseEvent convertMouseEvent(Component source,
  219.                                                MouseEvent sourceEvent,
  220.                                                Component destination) {
  221.         Point p = convertPoint(source,new Point(sourceEvent.getX(),
  222.                                                 sourceEvent.getY()),
  223.                                destination);
  224.         Component newSource;
  225.  
  226.         if(destination != null)
  227.             newSource = destination;
  228.         else
  229.             newSource = source;
  230.  
  231.         return new MouseEvent(newSource,
  232.                               sourceEvent.getID(),
  233.                               sourceEvent.getWhen(),
  234.                               sourceEvent.getModifiers(),
  235.                               p.x,p.y,
  236.                               sourceEvent.getClickCount(),
  237.                               sourceEvent.isPopupTrigger());
  238.     }
  239.  
  240.  
  241.     /**
  242.      * Convert a point from a component's coordinate system to
  243.      * screen coordinates.
  244.      *
  245.      * @param p  a Point object (converted to the new coordinate system)
  246.      * @param c  a Component object
  247.      */
  248.     public static void convertPointToScreen(Point p,Component c) {
  249.             Rectangle b;
  250.             int x,y;
  251.  
  252.             do {
  253.                 if(c instanceof JComponent) {
  254.                     x = ((JComponent)c).getX();
  255.                     y = ((JComponent)c).getY();
  256.                 } else if(c instanceof java.applet.Applet) {
  257.                     Point pp = c.getLocationOnScreen();
  258.                     x = pp.x;
  259.                     y = pp.y;
  260.                 } else {
  261.                     b = c.getBounds();
  262.                     x = b.x;
  263.                     y = b.y;
  264.                 }
  265.  
  266.                 p.x += x;
  267.                 p.y += y;
  268.  
  269.                 if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
  270.                     break;
  271.                 c = c.getParent();
  272.             } while(c != null);
  273.         }
  274.  
  275.     /**
  276.      * Convert a point from a screen coordinates to a component's 
  277.      * coordinate system
  278.      *
  279.      * @param p  a Point object (converted to the new coordinate system)
  280.      * @param c  a Component object
  281.      */
  282.     public static void convertPointFromScreen(Point p,Component c) {
  283.         Rectangle b;
  284.         int x,y;
  285.  
  286.         do {
  287.             if(c instanceof JComponent) {
  288.                 x = ((JComponent)c).getX();
  289.                 y = ((JComponent)c).getY();
  290.             }  else if(c instanceof java.applet.Applet) {
  291.                 Point pp = c.getLocationOnScreen();
  292.                 x = pp.x;
  293.                 y = pp.y;
  294.             } else {
  295.                 b = c.getBounds();
  296.                 x = b.x;
  297.                 y = b.y;
  298.             }
  299.  
  300.             p.x -= x;
  301.             p.y -= y;
  302.  
  303.             if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
  304.                 break;
  305.             c = c.getParent();
  306.         } while(c != null);
  307.     }
  308.  
  309.     /** Return <code>aComponent</code>'s window **/
  310.     public static Window windowForComponent(Component aComponent) {
  311.         for (Container p = aComponent.getParent(); p != null; p = p.getParent()) {
  312.             if (p instanceof Window) {
  313.                 return (Window)p;
  314.             }
  315.         }
  316.         return null;
  317.     }
  318.  
  319.     /**
  320.      * Return <code>true</code> if a component <code>a</code> descends from a component <code>b</code>
  321.      */
  322.     public static boolean isDescendingFrom(Component a,Component b) {
  323.         if(a == b)
  324.             return true;
  325.         for(Container p = a.getParent();p!=null;p=p.getParent())
  326.             if(p == b)
  327.                 return true;
  328.         return false;
  329.     }
  330.  
  331.  
  332.     /**
  333.      * Convenience to calculate an intersection of two rectangles without allocating a new rectangle
  334.      * Return dest.
  335.      */
  336.     public static Rectangle computeIntersection(int x,int y,int width,int height,Rectangle dest) {
  337.         int x1 = (x > dest.x) ? x : dest.x;
  338.         int x2 = ((x+width) < (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
  339.         int y1 = (y > dest.y) ? y : dest.y;
  340.         int y2 = ((y + height) < (dest.y + dest.height) ? (y+height) : (dest.y + dest.height));
  341.  
  342.         dest.x = x1;
  343.         dest.y = y1;
  344.         dest.width = x2 - x1;
  345.         dest.height = y2 - y1;
  346.         return dest;
  347.     }
  348.  
  349.     /**
  350.      * Convenience to calculate the union of two rectangles without allocating a new rectangle
  351.      * Return dest
  352.      */
  353.     public static Rectangle computeUnion(int x,int y,int width,int height,Rectangle dest) {
  354.         int x1 = (x < dest.x) ? x : dest.x;
  355.         int x2 = ((x+width) > (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
  356.         int y1 = (y < dest.y) ? y : dest.y;
  357.         int y2 = ((y+height) > (dest.y + dest.height)) ? (y+height) : (dest.y + dest.height);
  358.  
  359.         dest.x = x1;
  360.         dest.y = y1;
  361.         dest.width = (x2 - x1);
  362.         dest.height= (y2 - y1);
  363.         return dest;
  364.     }
  365.  
  366.     /**
  367.      * Convenience returning an array of rect representing the regions within
  368.      * <code>rectA</code> that do not overlap with <code>rectB</code>. If the
  369.      * two Rects do not overlap, returns an empty array
  370.      */
  371.     public static Rectangle[] computeDifference(Rectangle rectA,Rectangle rectB) {
  372.         if (rectB == null || !rectA.intersects(rectB) || isRectangleContainingRectangle(rectB,rectA)) {
  373.             return new Rectangle[0];
  374.         }
  375.  
  376.         Rectangle t = new Rectangle();
  377.         Rectangle a=null,b=null,c=null,d=null;
  378.         Rectangle result[];
  379.         int rectCount = 0;
  380.  
  381.         /* rectA contains rectB */
  382.         if (isRectangleContainingRectangle(rectA,rectB)) {
  383.             t.x = rectA.x; t.y = rectA.y; t.width = rectB.x - rectA.x; t.height = rectA.height;
  384.             if(t.width > 0 && t.height > 0) {
  385.                 a = new Rectangle(t);
  386.                 rectCount++;
  387.             }
  388.  
  389.             t.x = rectB.x; t.y = rectA.y; t.width = rectB.width; t.height = rectB.y - rectA.y;
  390.             if(t.width > 0 && t.height > 0) {
  391.                 b = new Rectangle(t);
  392.                 rectCount++;
  393.             }
  394.  
  395.             t.x = rectB.x; t.y = rectB.y + rectB.height; t.width = rectB.width;
  396.             t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
  397.             if(t.width > 0 && t.height > 0) {
  398.                 c = new Rectangle(t);
  399.                 rectCount++;
  400.             }
  401.  
  402.             t.x = rectB.x + rectB.width; t.y = rectA.y; t.width = rectA.x + rectA.width - (rectB.x + rectB.width);
  403.             t.height = rectA.height;
  404.             if(t.width > 0 && t.height > 0) {
  405.                 d = new Rectangle(t);
  406.                 rectCount++;
  407.             }
  408.         } else {
  409.             /* 1 */
  410.             if (rectB.x <= rectA.x && rectB.y <= rectA.y) {
  411.                 if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  412.  
  413.                     t.x = rectA.x; t.y = rectB.y + rectB.height;
  414.                     t.width = rectA.width; t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
  415.                     if(t.width > 0 && t.height > 0) {
  416.                         a = t;
  417.                         rectCount++;
  418.                     }
  419.                 } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  420.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  421.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  422.                     if(t.width > 0 && t.height > 0) {
  423.                         a = t;
  424.                         rectCount++;
  425.                     }
  426.                 } else {
  427.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  428.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
  429.                                 (rectB.y + rectB.height) - rectA.y);
  430.                     if(t.width > 0 && t.height > 0) {
  431.                         a = new Rectangle(t);
  432.                         rectCount++;
  433.                     }
  434.  
  435.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  436.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  437.                     if(t.width > 0 && t.height > 0) {
  438.                         b = new Rectangle(t);
  439.                         rectCount++;
  440.                     }
  441.                 }
  442.             } else if (rectB.x <= rectA.x && (rectB.y + rectB.height) >= (rectA.y + rectA.height)) {
  443.                 if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  444.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  445.                     if(t.width > 0 && t.height > 0) {
  446.                         a = t;
  447.                         rectCount++;
  448.                     }
  449.                 } else {
  450.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  451.                     if(t.width > 0 && t.height > 0) {
  452.                         a = new Rectangle(t);
  453.                         rectCount++;
  454.                     }
  455.                     t.setBounds((rectB.x + rectB.width), rectB.y,
  456.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
  457.                                 (rectA.y + rectA.height) - rectB.y);
  458.                     if(t.width > 0 && t.height > 0) {
  459.                         b = new Rectangle(t);
  460.                         rectCount++;
  461.                     }
  462.                 }
  463.             } else if (rectB.x <= rectA.x) {
  464.                 if ((rectB.x + rectB.width) >= (rectA.x + rectA.width)) {
  465.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  466.                     if(t.width>0 && t.height > 0) {
  467.                         a = new Rectangle(t);
  468.                         rectCount++;
  469.                     }
  470.  
  471.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  472.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  473.                     if(t.width > 0 && t.height > 0) {
  474.                         b = new Rectangle(t);
  475.                         rectCount++;
  476.                     }
  477.                 } else {
  478.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  479.                     if(t.width > 0 && t.height > 0) {
  480.                         a = new Rectangle(t);
  481.                         rectCount++;
  482.                     }
  483.  
  484.                     t.setBounds((rectB.x + rectB.width), rectB.y,
  485.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
  486.                                 rectB.height);
  487.                     if(t.width > 0 && t.height > 0) {
  488.                         b = new Rectangle(t);
  489.                         rectCount++;
  490.                     }
  491.  
  492.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  493.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  494.                     if(t.width > 0 && t.height > 0) {
  495.                         c = new Rectangle(t);
  496.                         rectCount++;
  497.                     }
  498.                 }
  499.             } else if (rectB.x <= (rectA.x + rectA.width) && (rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  500.                 if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  501.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  502.                     if(t.width > 0 && t.height > 0) {
  503.                         a = t;
  504.                         rectCount++;
  505.                     }
  506.                 } else if (rectB.y <= rectA.y) {
  507.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x,
  508.                                 (rectB.y + rectB.height) - rectA.y);
  509.                     if(t.width > 0 && t.height > 0) {
  510.                         a = new Rectangle(t);
  511.                         rectCount++;
  512.                     }
  513.  
  514.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  515.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  516.                     if(t.width > 0 && t.height > 0) {
  517.                         b = new Rectangle(t);
  518.                         rectCount++;
  519.                     }
  520.                 } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  521.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  522.                     if(t.width > 0 && t.height > 0) {
  523.                         a = new Rectangle(t);
  524.                         rectCount++;
  525.                     }
  526.  
  527.                     t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
  528.                                 (rectA.y + rectA.height) - rectB.y);
  529.                     if(t.width > 0 && t.height > 0) {
  530.                         b = new Rectangle(t);
  531.                         rectCount++;
  532.                     }
  533.                 } else {
  534.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  535.                     if(t.width > 0 && t.height > 0) {
  536.                         a = new Rectangle(t);
  537.                         rectCount++;
  538.                     }
  539.  
  540.                     t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
  541.                                 rectB.height);
  542.                     if(t.width > 0 && t.height > 0) {
  543.                         b = new Rectangle(t);
  544.                         rectCount++;
  545.                     }
  546.  
  547.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  548.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  549.                     if(t.width > 0 && t.height > 0) {
  550.                         c = new Rectangle(t);
  551.                         rectCount++;
  552.                     }
  553.                 }
  554.             } else if (rectB.x >= rectA.x && (rectB.x + rectB.width) <= (rectA.x + rectA.width)) {
  555.                 if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  556.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  557.                     if(t.width > 0 && t.height > 0) {
  558.                         a = new Rectangle(t);
  559.                         rectCount++;
  560.                     }
  561.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  562.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  563.                     if(t.width > 0 && t.height > 0) {
  564.                         b = new Rectangle(t);
  565.                         rectCount++;
  566.                     }
  567.                 } else if (rectB.y <= rectA.y) {
  568.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  569.                     if(t.width > 0 && t.height > 0) {
  570.                         a = new Rectangle(t);
  571.                         rectCount++;
  572.                     }
  573.  
  574.                     t.setBounds(rectB.x, (rectB.y + rectB.height),
  575.                                 rectB.width,
  576.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  577.                     if(t.width > 0 && t.height > 0) {
  578.                         b = new Rectangle(t);
  579.                         rectCount++;
  580.                     }
  581.  
  582.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  583.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  584.                     if(t.width > 0 && t.height > 0) {
  585.                         c = new Rectangle(t);
  586.                         rectCount++;
  587.                     }
  588.                 } else {
  589.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  590.                     if(t.width > 0 && t.height > 0) {
  591.                         a = new Rectangle(t);
  592.                         rectCount++;
  593.                     }
  594.  
  595.                     t.setBounds(rectB.x, rectA.y, rectB.width,
  596.                                 rectB.y - rectA.y);
  597.                     if(t.width > 0 && t.height > 0) {
  598.                         b = new Rectangle(t);
  599.                         rectCount++;
  600.                     }
  601.  
  602.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  603.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  604.                     if(t.width > 0 && t.height > 0) {
  605.                         c = new Rectangle(t);
  606.                         rectCount++;
  607.                     }
  608.                 }
  609.             }
  610.         }
  611.  
  612.         result = new Rectangle[rectCount];
  613.         rectCount = 0;
  614.         if(a != null)
  615.             result[rectCount++] = a;
  616.         if(b != null)
  617.             result[rectCount++] = b;
  618.         if(c != null)
  619.             result[rectCount++] = c;
  620.         if(d != null)
  621.             result[rectCount++] = d;
  622.         return result;
  623.     }
  624.  
  625.     /**
  626.      * Returns true if the mouse event specifies the left mouse button.
  627.      *
  628.      * @param anEvent  a MouseEvent object
  629.      * @return true if the left mouse button was active
  630.      */
  631.     public static boolean isLeftMouseButton(MouseEvent anEvent) {
  632.          if (is1dot2) {
  633.              return ((anEvent.getModifiers() & InputEvent.BUTTON1_MASK) != 0);
  634.          }
  635.          return ((anEvent.getModifiers() & InputEvent.BUTTON1_MASK) != 0 ||
  636.                   // Workaround for Solaris not setting BUTTON1_MASK
  637.                   // Not needed in 1.2 where BUTTON1_MASK is correctly set.
  638.                   (anEvent.getModifiers() & (InputEvent.BUTTON2_MASK |
  639.                                              InputEvent.BUTTON3_MASK)) == 0);
  640.     }
  641.  
  642.     /**
  643.      * Returns true if the mouse event specifies the middle mouse button.
  644.      *
  645.      * @param anEvent  a MouseEvent object
  646.      * @return true if the middle mouse button was active
  647.      */
  648.     public static boolean isMiddleMouseButton(MouseEvent anEvent) {
  649.         return ((anEvent.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK);
  650.     }
  651.  
  652.     /**
  653.      * Returns true if the mouse event specifies the right mouse button.
  654.      *
  655.      * @param anEvent  a MouseEvent object
  656.      * @return true if the right mouse button was active
  657.      */
  658.     public static boolean isRightMouseButton(MouseEvent anEvent) {
  659.         return ((anEvent.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK);
  660.     }
  661.  
  662.     /*
  663.      * Returns whether this is being run on a JDK 1.2 or later VM.
  664.      * This is a system-wide, rather than AppContext-wide, state.
  665.      */
  666.     /*package-private*/ static boolean is1dot2 = true;
  667.  
  668.     static {
  669.         try {
  670.             // Test if method introduced in 1.2 is available.
  671.             Method m = Toolkit.class.getMethod("getMaximumCursorColors", null);
  672.             is1dot2 = (m != null);
  673.         } catch (NoSuchMethodException e) {
  674.             is1dot2 = false;
  675.         }
  676.  
  677.         // Warn if running wrong version of this class for this JDK.
  678.         
  679.           if (!is1dot2) {
  680.               System.err.println("warning: running 1.2 version of SwingUtilities");
  681.           }
  682.           
  683.  
  684.  
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691.     }
  692.  
  693.     /**
  694.      * Compute the width of the string using a font with the specified
  695.      * "metrics" (sizes).
  696.      *
  697.      * @param fm   a FontMetrics object to compute with
  698.      * @param str  the String to compute
  699.      * @return an int containing the string width
  700.      */
  701.     public static int computeStringWidth(FontMetrics fm,String str) {
  702.         if (is1dot2) {
  703.             // You can't assume that a string's width is the sum of its
  704.             // characters' widths in Java2D -- it may be smaller due to
  705.             // kerning, etc.
  706.             return fm.stringWidth(str);
  707.         }
  708.  
  709.         int w[] = fm.getWidths();
  710.         int i,c;
  711.         int result = 0;
  712.         char ch;
  713.         for(i=0,c=str.length() ; i < c ; i++) {
  714.             ch = str.charAt(i);
  715.             if(ch > 255)
  716.                 return fm.stringWidth(str);
  717.             else
  718.                 result += w[(int)ch];
  719.         }
  720.         return result;
  721.     }
  722.  
  723.  
  724.     /**
  725.      * Compute and return the location of the icons origin, the
  726.      * location of origin of the text baseline, and a possibly clipped
  727.      * version of the compound labels string.  Locations are computed
  728.      * relative to the viewR rectangle.
  729.      * The JComponents orientation (LEADING/TRAILING) will also be taken
  730.      * into account and translated into LEFT/RIGHT values accordingly.
  731.      */
  732.     public static String layoutCompoundLabel(JComponent c,
  733.                                              FontMetrics fm,
  734.                                              String text,
  735.                                              Icon icon,
  736.                                              int verticalAlignment,
  737.                                              int horizontalAlignment,
  738.                                              int verticalTextPosition,
  739.                                              int horizontalTextPosition,
  740.                                              Rectangle viewR,
  741.                                              Rectangle iconR,
  742.                                              Rectangle textR,
  743.                                              int textIconGap)
  744.     {
  745.         boolean orientationIsLeftToRight = true;
  746.         int     hAlign = horizontalAlignment;
  747.         int     hTextPos = horizontalTextPosition;
  748.  
  749.         
  750.         if (c != null) {
  751.             if (!(c.getComponentOrientation().isLeftToRight())) {
  752.                 orientationIsLeftToRight = false;
  753.             }
  754.         }
  755.         
  756.  
  757.         // Translate LEADING/TRAILING values in horizontalAlignment
  758.         // to LEFT/RIGHT values depending on the components orientation
  759.         switch (horizontalAlignment) {
  760.         case LEADING: 
  761.             hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
  762.             break;
  763.         case TRAILING: 
  764.             hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
  765.             break;
  766.         }
  767.  
  768.         // Translate LEADING/TRAILING values in horizontalTextPosition
  769.         // to LEFT/RIGHT values depending on the components orientation
  770.         switch (horizontalTextPosition) {
  771.         case LEADING: 
  772.             hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
  773.             break;
  774.         case TRAILING: 
  775.             hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
  776.             break;
  777.         }
  778.  
  779.         return layoutCompoundLabel(fm,
  780.                                    text,
  781.                                    icon,
  782.                                    verticalAlignment,
  783.                                    hAlign,
  784.                                    verticalTextPosition,
  785.                                    hTextPos,
  786.                                    viewR,
  787.                                    iconR,
  788.                                    textR,
  789.                                    textIconGap);
  790.     }
  791.  
  792.  
  793.     /**
  794.      * Compute and return the location of the icons origin, the
  795.      * location of origin of the text baseline, and a possibly clipped
  796.      * version of the compound labels string.  Locations are computed
  797.      * relative to the viewR rectangle.
  798.      * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
  799.      * values in horizontalTextPosition (they will default to RIGHT) and in
  800.      * horizontalAlignment (they will default to CENTER).
  801.      * Use the other version of layoutCompoundLabel() instead.
  802.      */
  803.     public static String layoutCompoundLabel(
  804.         FontMetrics fm,
  805.         String text,
  806.         Icon icon,
  807.         int verticalAlignment,
  808.         int horizontalAlignment,
  809.         int verticalTextPosition,
  810.         int horizontalTextPosition,
  811.         Rectangle viewR,
  812.         Rectangle iconR,
  813.         Rectangle textR,
  814.         int textIconGap)
  815.     {
  816.         /* Initialize the icon bounds rectangle iconR.
  817.          */
  818.  
  819.         if (icon != null) {
  820.             iconR.width = icon.getIconWidth();
  821.             iconR.height = icon.getIconHeight();
  822.         }
  823.         else {
  824.             iconR.width = iconR.height = 0;
  825.         }
  826.  
  827.         /* Initialize the text bounds rectangle textR.  If a null
  828.          * or and empty String was specified we substitute "" here
  829.          * and use 0,0,0,0 for textR.
  830.          */
  831.  
  832.         boolean textIsEmpty = (text == null) || text.equals("");
  833.  
  834.         if (textIsEmpty) {
  835.             textR.width = textR.height = 0;
  836.             text = "";
  837.         }
  838.         else {
  839.             textR.width = computeStringWidth(fm,text);
  840.             textR.height = fm.getHeight();
  841.         }
  842.  
  843.         /* Unless both text and icon are non-null, we effectively ignore
  844.          * the value of textIconGap.  The code that follows uses the
  845.          * value of gap instead of textIconGap.
  846.          */
  847.  
  848.         int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
  849.  
  850.         if (!textIsEmpty) {
  851.  
  852.             /* If the label text string is too wide to fit within the available
  853.              * space "..." and as many characters as will fit will be
  854.              * displayed instead.
  855.              */
  856.  
  857.             int availTextWidth;
  858.  
  859.             if (horizontalTextPosition == CENTER) {
  860.                 availTextWidth = viewR.width;
  861.             }
  862.             else {
  863.                 availTextWidth = viewR.width - (iconR.width + gap);
  864.             }
  865.  
  866.  
  867.             if (textR.width > availTextWidth) {
  868.                 String clipString = "...";
  869.                 int totalWidth = computeStringWidth(fm,clipString);
  870.                 int nChars;
  871.                 for(nChars = 0; nChars < text.length(); nChars++) {
  872.                     totalWidth += fm.charWidth(text.charAt(nChars));
  873.                     if (totalWidth > availTextWidth) {
  874.                         break;
  875.                     }
  876.                 }
  877.                 text = text.substring(0, nChars) + clipString;
  878.                 textR.width = computeStringWidth(fm,text);
  879.             }
  880.         }
  881.  
  882.  
  883.         /* Compute textR.x,y given the verticalTextPosition and
  884.          * horizontalTextPosition properties
  885.          */
  886.  
  887.         if (verticalTextPosition == TOP) {
  888.             if (horizontalTextPosition != CENTER) {
  889.                 textR.y = 0;
  890.             }
  891.             else {
  892.                 textR.y = -(textR.height + gap);
  893.             }
  894.         }
  895.         else if (verticalTextPosition == CENTER) {
  896.             textR.y = (iconR.height / 2) - (textR.height / 2);
  897.         }
  898.         else { // (verticalTextPosition == BOTTOM)
  899.             if (horizontalTextPosition != CENTER) {
  900.                 textR.y = iconR.height - textR.height;
  901.             }
  902.             else {
  903.                 textR.y = (iconR.height + gap);
  904.             }
  905.         }
  906.  
  907.         if (horizontalTextPosition == LEFT) {
  908.             textR.x = -(textR.width + gap);
  909.         }
  910.         else if (horizontalTextPosition == CENTER) {
  911.             textR.x = (iconR.width / 2) - (textR.width / 2);
  912.         }
  913.         else { // (horizontalTextPosition == RIGHT)
  914.             textR.x = (iconR.width + gap);
  915.         }
  916.  
  917.         /* labelR is the rectangle that contains iconR and textR.
  918.          * Move it to its proper position given the labelAlignment
  919.          * properties.
  920.          *
  921.          * To avoid actually allocating a Rectangle, Rectangle.union
  922.          * has been inlined below.
  923.          */
  924.         int labelR_x = Math.min(iconR.x, textR.x);
  925.         int labelR_width = Math.max(iconR.x + iconR.width,
  926.                                     textR.x + textR.width) - labelR_x;
  927.         int labelR_y = Math.min(iconR.y, textR.y);
  928.         int labelR_height = Math.max(iconR.y + iconR.height,
  929.                                      textR.y + textR.height) - labelR_y;
  930.  
  931.         int dx, dy;
  932.  
  933.         if (verticalAlignment == TOP) {
  934.             dy = viewR.y - labelR_y;
  935.         }
  936.         else if (verticalAlignment == CENTER) {
  937.             dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
  938.         }
  939.         else { // (verticalAlignment == BOTTOM)
  940.             dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
  941.         }
  942.  
  943.         if (horizontalAlignment == LEFT) {
  944.             dx = viewR.x - labelR_x;
  945.         }
  946.         else if (horizontalAlignment == RIGHT) {
  947.             dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
  948.         }
  949.         else { // (horizontalAlignment == CENTER)
  950.             dx = (viewR.x + (viewR.width / 2)) -
  951.                  (labelR_x + (labelR_width / 2));
  952.         }
  953.  
  954.         /* Translate textR and glypyR by dx,dy.
  955.          */
  956.  
  957.         textR.x += dx;
  958.         textR.y += dy;
  959.  
  960.         iconR.x += dx;
  961.         iconR.y += dy;
  962.  
  963.         return text;
  964.     }
  965.  
  966.  
  967.     /**
  968.      * Paint a component c on an abitrary graphics g in the
  969.      * specified rectangle, specifying the rectangle's upper left corner
  970.      * and size.  The component is reparented to a private
  971.      * container (whose parent becomes p) which prevents c.validate() and
  972.      * and c.repaint() calls from propogating up the tree.  The intermediate
  973.      * container has no other effect.
  974.      *
  975.      * @param g  the Graphics object to draw on
  976.      * @param c  the Component to draw
  977.      * @param p  the intermedate Container
  978.      * @param x  an int specifying the left side of the area draw in, in pixels,
  979.      *           measured from the left edge of the graphics context
  980.      * @param y  an int specifying the top of the area to draw in, in pixels
  981.      *           measured down from the top edge of the graphics context
  982.      * @param w  an int specifying the width of the area draw in, in pixels
  983.      * @param h  an int specifying the height of the area draw in, in pixels
  984.      */
  985.     public static void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
  986.         getCellRendererPane(c, p).paintComponent(g, c, p, x, y, w, h,false);
  987.     }
  988.  
  989.     /**
  990.      * Paint a component c on an abitrary graphics g in the
  991.      * specified rectangle, specifying a Rectangle object.  The component is reparented to a private
  992.      * container (whose parent becomes p) which prevents c.validate() and
  993.      * and c.repaint() calls from propogating up the tree.  The intermediate
  994.      * container has no other effect.
  995.      *
  996.      * @param g  the Graphics object to draw on
  997.      * @param c  the Component to draw
  998.      * @param p  the intermedate Container
  999.      * @param r  the Rectangle to draw in
  1000.      */
  1001.     public static void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
  1002.         paintComponent(g, c, p, r.x, r.y, r.width, r.height);
  1003.     }
  1004.  
  1005.  
  1006.     /*
  1007.      * Ensure that cell renderer c has a ComponentShell parent and that
  1008.      * the shells parent is p.
  1009.      */
  1010.     private static CellRendererPane getCellRendererPane(Component c, Container p) {
  1011.         Container shell = c.getParent();
  1012.         if (shell instanceof CellRendererPane) {
  1013.             if (shell.getParent() != p) {
  1014.                 p.add(shell);
  1015.             }
  1016.         } else {
  1017.             shell = new CellRendererPane();
  1018.             shell.add(c);
  1019.             p.add(shell);
  1020.         }
  1021.         return (CellRendererPane)shell;
  1022.     }
  1023.  
  1024.     /**
  1025.      * A simple minded look and feel change: ask each node in the tree
  1026.      * to updateUI(), i.e. to initialize its UI property with the
  1027.      * current look and feel.
  1028.      */
  1029.     public static void updateComponentTreeUI(Component c) {
  1030.         updateComponentTreeUI0(c);
  1031.         c.invalidate();
  1032.         c.validate();
  1033.         c.repaint();
  1034.     }
  1035.  
  1036.     private static void updateComponentTreeUI0(Component c) {
  1037.         if (c instanceof JComponent) {
  1038.             ((JComponent) c).updateUI();
  1039.         }
  1040.         Component[] children = null;
  1041.         if (c instanceof JMenu) {
  1042.             children = ((JMenu)c).getMenuComponents();
  1043.         }
  1044.         else if (c instanceof Container) {
  1045.             children = ((Container)c).getComponents();
  1046.         }
  1047.         if (children != null) {
  1048.             for(int i = 0; i < children.length; i++) {
  1049.                 updateComponentTreeUI0(children[i]);
  1050.             }
  1051.         }
  1052.     }
  1053.  
  1054.  
  1055.     /**
  1056.      * Causes <i>doRun.run()</i> to be executed asynchronously on the
  1057.      * AWT event dispatching thread.  This will happen after all
  1058.      * pending AWT events have been processed.  This method should
  1059.      * be used when an application thread needs to update the GUI.
  1060.      * In the following example the invokeAndWait() calls queues
  1061.      * the doHelloWorld Runnable for the event dispatching thread and
  1062.      * then prints a message.
  1063.      * <pre>
  1064.      * Runnable doHelloWorld = new Runnable() {
  1065.      *     public void run() {
  1066.      *         System.out.println("Hello World on " + Thread.currentThread());
  1067.      *     }
  1068.      * };
  1069.      *
  1070.      * SwingUtilities.invokeAndWait(doHelloWorld);
  1071.      * System.out.println("Waiting ... ");
  1072.      * </pre>
  1073.      * If invokeAndWait is called from the event dispatching thread,
  1074.      * e.g. from a JButtons ActionListener, the <i>doRun.run()</i> will
  1075.      * still be deferred till all pending events have been processed.
  1076.      * Note that if the <i>doRun.run()</i> throws an uncaught exception
  1077.      * the event dispatching thread will unwind (not the current thread).
  1078.      * <p>
  1079.      * Additional documentation and examples for this method can be
  1080.      * found in <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">.
  1081.      *
  1082.      * @see #invokeAndWait
  1083.      */
  1084.     public static void invokeLater(Runnable doRun) {
  1085.         SystemEventQueueUtilities.postRunnable(doRun, null);
  1086.     }
  1087.  
  1088.  
  1089.     /**
  1090.      * Causes <i>doRun.run()</i> to be executed synchronously on the
  1091.      * AWT event dispatching thread.  This call will block until
  1092.      * all pending AWT events have been processed and (then)
  1093.      * <i>doRun.run()</i> returns. This method should
  1094.      * be used when an application thread needs to update the GUI.
  1095.      * It should not be called from the EventDispatchThread.
  1096.      * Here's an example that creates a new application thread
  1097.      * that uses invokeAndWait() to print a string from the event
  1098.      * dispatching thread and then, when that's finished, print
  1099.      * a string from the application thread.
  1100.      * <pre>
  1101.      * final Runnable doHelloWorld = new Runnable() {
  1102.      *     public void run() {
  1103.      *         System.out.println("Hello World on " + Thread.currentThread());
  1104.      *     }
  1105.      * };
  1106.      *
  1107.      * Thread appThread = new Thread() {
  1108.      *     public void run() {
  1109.      *         try {
  1110.      *             SwingUtilities.invokeAndWait(doHelloWorld);
  1111.      *         }
  1112.      *         catch (Exception e) {
  1113.      *             e.printStackTrace();
  1114.      *         }
  1115.      *         System.out.println("Finished on " + Thread.currentThread());
  1116.      *     }
  1117.      * };
  1118.      * appThread.start();
  1119.      * </pre>
  1120.      * Note that if the Runnable.run() method throws an uncaught exception
  1121.      * (on the event dispatching thread) it's caught and rethrown, as
  1122.      * an InvocationTargetException, on the callers thread.
  1123.      * <p>
  1124.      * Additional documentation and examples for this method can be
  1125.      * found in <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">.
  1126.      *
  1127.      * @exception  InterruptedException If we're interrupted while waiting for
  1128.      *             the event dispatching thread to finish excecuting <i>doRun.run()</i>
  1129.      * @exception  InvocationTargetException  If <i>doRun.run()</i> throws
  1130.      *
  1131.      * @see #invokeLater
  1132.      */
  1133.     public static void invokeAndWait(final Runnable doRun)
  1134.         throws InterruptedException, InvocationTargetException
  1135.     {
  1136.         if(isEventDispatchThread ()) {
  1137.             throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
  1138.         }
  1139.  
  1140.         Object lock = new Object() {
  1141.             public String toString() {
  1142.                 return "SwingUtilities.invokeAndWait() lock for " + doRun;
  1143.             }
  1144.         };
  1145.  
  1146.         Exception exc = null;
  1147.         synchronized(lock) {
  1148.             exc = SystemEventQueueUtilities.postRunnable(doRun, lock);
  1149.             lock.wait();
  1150.         }
  1151.  
  1152.         if (exc != null) {
  1153.             throw new InvocationTargetException(exc);
  1154.         }
  1155.     }
  1156.  
  1157.  
  1158.     private static Class eventDispatchThreadClass = null;
  1159.  
  1160.     /**
  1161.      * Returns true if the current thread is an AWT event dispatching thread.
  1162.      * @return true if the current thread is an AWT event dispatching thread
  1163.      */
  1164.     public static boolean isEventDispatchThread()
  1165.     {
  1166.         Thread currentThread = Thread.currentThread();
  1167.  
  1168.         /* The first time we're called on what appears to be the event
  1169.          * dispatching thread, we stash the threads class in
  1170.          * eventDispatchThreadClass.  Subsequently we effectively
  1171.          * return eventDispatchThreadClass instanceof Thread.currentThread().
  1172.          */
  1173.  
  1174.         if (eventDispatchThreadClass == null) {
  1175.             Class currentThreadClass = currentThread.getClass();
  1176.  
  1177.             /* This test is a crock.  It's known to work on all of the popular
  1178.              * JDK1.1 implementations available as of January 1998.
  1179.              */
  1180.             if((currentThreadClass.getName().indexOf("EventDispatchThread") >= 0) ||
  1181.                (currentThreadClass.getName().indexOf("JMEventQueue") >= 0)) {
  1182.                 eventDispatchThreadClass = currentThreadClass;
  1183.                 return true;
  1184.             }
  1185.             else {
  1186.                 return false;
  1187.             }
  1188.         }
  1189.         return eventDispatchThreadClass.isInstance(currentThread);
  1190.     }
  1191.  
  1192.  
  1193.     /*
  1194.      * --- Accessibility Support ---
  1195.      *
  1196.      */
  1197.  
  1198.     /**
  1199.      * Get the index of this object in its accessible parent.
  1200.      *
  1201.      * @return -1 of this object does not have an accessible parent.
  1202.      * Otherwise, the index of the child in its accessible parent.
  1203.      */
  1204.     public static int getAccessibleIndexInParent(Component c) {
  1205.         int index = -1;
  1206.         Container parent = c.getParent();
  1207.         if (parent != null && parent instanceof Accessible) {
  1208.             Component ca[] = parent.getComponents();
  1209.             for (int i = 0; i < ca.length; i++) {
  1210.                 if (ca[i] instanceof Accessible) {
  1211.                     index++;
  1212.                 }
  1213.                 if (c.equals(ca[i])) {
  1214.                     return index;
  1215.                 }
  1216.             }
  1217.         }
  1218.         return -1;
  1219.     }
  1220.  
  1221.     /**
  1222.      * Returns the Accessible child contained at the local coordinate
  1223.      * Point, if one exists.
  1224.      *
  1225.      * @return the Accessible at the specified location, if it exists
  1226.      */
  1227.     public static Accessible getAccessibleAt(Component c, Point p) {
  1228.         if (c instanceof Accessible) {
  1229.             Accessible a = (Accessible) c;
  1230.             if (a != null) {
  1231.                 AccessibleContext ac = a.getAccessibleContext();
  1232.                 if (ac != null) {
  1233.                     AccessibleComponent acmp;
  1234.                     Point location;
  1235.                     int nchildren = ac.getAccessibleChildrenCount();
  1236.                     for (int i=0; i < nchildren; i++) {
  1237.                         a = ac.getAccessibleChild(i);
  1238.                         if ((a != null)) {
  1239.                             ac = a.getAccessibleContext();
  1240.                             if (ac != null) {
  1241.                                 acmp = ac.getAccessibleComponent();
  1242.                                 if ((acmp != null) && (acmp.isShowing())) {
  1243.                                     location = acmp.getLocation();
  1244.                                     Point np = new Point(p.x-location.x,
  1245.                                                          p.y-location.y);
  1246.                                     if (acmp.contains(np)){
  1247.                                         return a;
  1248.                                     }
  1249.                                 }
  1250.                             }
  1251.                         }
  1252.                     }
  1253.                 }
  1254.             }
  1255.             return (Accessible) c;
  1256.         } else {
  1257.             Component ret = c;
  1258.             if (!c.contains(p.x,p.y)) {
  1259.                 ret = null;
  1260.             } else if (c instanceof Container) {
  1261.                 Container cnt = (Container) c;
  1262.                 int ncomponents = cnt.getComponentCount();
  1263.                 for (int i=0; i < ncomponents; i++) {
  1264.                     Component comp = cnt.getComponent(i);
  1265.                     if ((comp != null) && comp.isShowing()) {
  1266.                         Point location = comp.getLocation();
  1267.                         if (comp.contains(p.x-location.x,p.y-location.y)) {
  1268.                             ret = comp;
  1269.                         }
  1270.                     }
  1271.                 }
  1272.             }
  1273.             if (ret instanceof Accessible) {
  1274.                 return (Accessible) ret;
  1275.             }
  1276.         }
  1277.         return null;
  1278.     }
  1279.  
  1280.     /**
  1281.      * Get the state of this object.
  1282.      *
  1283.      * @return an instance of AccessibleStateSet containing the current state
  1284.      * set of the object
  1285.      * @see AccessibleState
  1286.      */
  1287.     public static AccessibleStateSet getAccessibleStateSet(Component c) {
  1288.         AccessibleStateSet states = new AccessibleStateSet();
  1289.         if (c.isEnabled()) {
  1290.             states.add(AccessibleState.ENABLED);
  1291.         }
  1292.         if (c.isFocusTraversable()) {
  1293.             states.add(AccessibleState.FOCUSABLE);
  1294.         }
  1295.         if (c.isVisible()) {
  1296.             states.add(AccessibleState.VISIBLE);
  1297.         }
  1298.         if (c.isShowing()) {
  1299.             states.add(AccessibleState.SHOWING);
  1300.         }
  1301.         // [[[FIXME:  WDW - for JDK1.2 this code can be replaced with
  1302.         //            c.hasFocus()]]]
  1303.         for (Container p = c.getParent(); p != null; p = p.getParent()) {
  1304.             if (p instanceof Window) {
  1305.                 if (((Window)p).getFocusOwner() == c) {
  1306.                     states.add(AccessibleState.FOCUSED);
  1307.                 }
  1308.             }
  1309.         }
  1310.         if (c instanceof Accessible) {
  1311.             AccessibleContext ac = ((Accessible) c).getAccessibleContext();
  1312.             if (ac != null) {
  1313.                 Accessible ap = ac.getAccessibleParent();
  1314.                 if (ap != null) {
  1315.                     AccessibleContext pac = ap.getAccessibleContext();
  1316.                     if (pac != null) {
  1317.                         AccessibleSelection as = pac.getAccessibleSelection();
  1318.                         if (as != null) {
  1319.                             states.add(AccessibleState.SELECTABLE);
  1320.                             int i = ac.getAccessibleIndexInParent();
  1321.                             if (i >= 0) {
  1322.                                 if (as.isAccessibleChildSelected(i)) {
  1323.                                     states.add(AccessibleState.SELECTED);
  1324.                                 }
  1325.                             }
  1326.                         }
  1327.                     }
  1328.                 }
  1329.             }
  1330.         }
  1331.         if (c instanceof JComponent) {
  1332.             if (((JComponent) c).isOpaque()) {
  1333.                 states.add(AccessibleState.OPAQUE);
  1334.             }
  1335.         }
  1336.         return states;
  1337.     }
  1338.  
  1339.     /**
  1340.      * Returns the number of accessible children in the object.  If all
  1341.      * of the children of this object implement Accessible, than this
  1342.      * method should return the number of children of this object.
  1343.      *
  1344.      * @return the number of accessible children in the object.
  1345.      */
  1346.     public static int getAccessibleChildrenCount(Component c) {
  1347.         int count = 0;
  1348.         if (c instanceof Container) {
  1349.             Component[] children = ((Container) c).getComponents();
  1350.             for (int i = 0; i < children.length; i++) {
  1351.                 if (children[i] instanceof Accessible) {
  1352.                     count++;
  1353.                 }
  1354.             }
  1355.         }
  1356.         return count;
  1357.     }
  1358.  
  1359.     /**
  1360.      * Return the nth Accessible child of the object.
  1361.      *
  1362.      * @param i zero-based index of child
  1363.      * @return the nth Accessible child of the object
  1364.      */
  1365.     public static Accessible getAccessibleChild(Component c, int i) {
  1366.         if (c instanceof Container) {
  1367.             Component[] children = ((Container) c).getComponents();
  1368.             int count = 0;
  1369.             for (int j = 0; j < children.length; j++) {
  1370.                 if (children[j] instanceof Accessible) {
  1371.                     if (count == i) {
  1372.                         return (Accessible) children[j];
  1373.                     } else {
  1374.                         count++;
  1375.                     }
  1376.                 }
  1377.             }
  1378.         }
  1379.         return null;
  1380.     }
  1381.  
  1382.     /**
  1383.      * Return the child component which has focus, if any.  The HotJava
  1384.      * SecurityManager forbids applet access to getFocusOwner(), so if the
  1385.      * component is an applet, we check whether a JComponent has focus.
  1386.      * Non-Swing components in an applet on HotJava are out-of-luck,
  1387.      * unfortunately.
  1388.      */
  1389.     public static Component findFocusOwner(Component c) {
  1390.         if (c instanceof Window) {
  1391.             return ((Window)c).getFocusOwner();
  1392.         }
  1393.  
  1394.         if (c instanceof JComponent && ((JComponent)c).hasFocus()) {
  1395.             return c;
  1396.         }
  1397.         if (c instanceof Container) {
  1398.             int n = ((Container)c).countComponents();
  1399.             for (int i = 0; i < n; i++) {
  1400.                 Component focusOwner =
  1401.                     findFocusOwner(((Container)c).getComponent(i));
  1402.                 if (focusOwner != null) {
  1403.                     return focusOwner;
  1404.                 }
  1405.             }
  1406.             return null;
  1407.         } else {
  1408.             return null;  // Component doesn't have hasFocus().
  1409.         }
  1410.     }
  1411.  
  1412.     /**
  1413.      * If c is a JRootPane descendant return its JRootPane ancestor.
  1414.      * If c is a RootPaneContainer then return its JRootPane.
  1415.      * @return the JRootPane for Component c or null.
  1416.      */
  1417.     public static JRootPane getRootPane(Component c) {
  1418.         if (c instanceof RootPaneContainer) {
  1419.             return ((RootPaneContainer)c).getRootPane();
  1420.         }
  1421.         for( ; c != null; c = c.getParent()) {
  1422.             if (c instanceof JRootPane) {
  1423.                 return (JRootPane)c;
  1424.             }
  1425.         }
  1426.         return null;
  1427.     }
  1428.  
  1429.  
  1430.     /**
  1431.      * Returns the root component for the current component tree.
  1432.      * @return the first ancestor of c that's a Window or the last Applet ancestor
  1433.      */
  1434.     public static Component getRoot(Component c) {
  1435.         Component applet = null;
  1436.         for(Component p = c; p != null; p = p.getParent()) {
  1437.             if (p instanceof Window) {
  1438.                 return p;
  1439.             }
  1440.             if (p instanceof Applet) {
  1441.                 applet = p;
  1442.             }
  1443.         }
  1444.         return applet;
  1445.     }
  1446.  
  1447.  
  1448.  
  1449.     // Don't use String, as it's not guaranteed to be unique in a Hashtable.
  1450.     private static final Object sharedOwnerFrameKey =
  1451.        new StringBuffer("SwingUtilities.sharedOwnerFrame");
  1452.  
  1453.     /**
  1454.      * Returns a toolkit-private, shared, invisible Frame
  1455.      * to be the owner for JDialogs and JWindows created with
  1456.      * null owners.
  1457.      */
  1458.     static Frame getSharedOwnerFrame() {
  1459.         Frame sharedOwnerFrame =
  1460.             (Frame)SwingUtilities.appContextGet(sharedOwnerFrameKey);
  1461.         if (sharedOwnerFrame == null) {
  1462.             sharedOwnerFrame = new Frame() {
  1463.                 public void show() {
  1464.                     // This frame can never be shown
  1465.                 }
  1466.                 public synchronized void dispose() {
  1467.                     try {
  1468.                         getToolkit().getSystemEventQueue();
  1469.                         super.dispose();
  1470.                     } catch (Exception e) {
  1471.                         // untrusted code not allowed to dispose
  1472.                     }
  1473.                 }
  1474.             };
  1475.             SwingUtilities.appContextPut(sharedOwnerFrameKey,
  1476.                                          sharedOwnerFrame);
  1477.         }
  1478.         return sharedOwnerFrame;
  1479.     }
  1480.  
  1481.     // The following static var and methods are a temporary
  1482.     // workaround for a Solaris bug where disposing modal dialogs
  1483.     // can sometimes cause a segmentation violation. Once this
  1484.     // AWT bug is fixed and available in browsers, we can remove
  1485.     // this workaround.
  1486.     private static final Object dialogsKey =
  1487.         new StringBuffer("SwingUtilities.dialogs");
  1488.  
  1489.     static JDialog getRecycledModalDialog(Frame frame, String title) {
  1490.         Vector dialogs = (Vector)SwingUtilities.appContextGet(dialogsKey);
  1491.         if (dialogs == null) {
  1492.             dialogs = new Vector();
  1493.             SwingUtilities.appContextPut(dialogsKey, dialogs);
  1494.         }
  1495.         JDialog dialog = null;
  1496.         synchronized(dialogs) {
  1497.             for(int i = 0; i < dialogs.size(); i++) {
  1498.                 dialog = (JDialog)dialogs.elementAt(i);
  1499.                 if (dialog.getParent() == frame) {
  1500.                     //System.out.println("Found available dialog: "+dialog);
  1501.                     dialogs.removeElement(dialog);
  1502.                     dialog.setTitle(title);
  1503.                     return dialog;
  1504.                 }
  1505.             }
  1506.             dialog = new JDialog(frame, title, true);
  1507.             //System.out.println("Created new dialog: "+dialog);
  1508.         }
  1509.         return dialog;
  1510.     }
  1511.  
  1512.     static void recycleModalDialog(JDialog dialog) {
  1513.         Vector dialogs = (Vector)SwingUtilities.appContextGet(dialogsKey);
  1514.         synchronized(dialogs) {
  1515.             dialog.getContentPane().removeAll();
  1516.             dialogs.addElement(dialog);
  1517.         }
  1518.     }
  1519.  
  1520.  
  1521.     /* Don't make these AppContext accessors public or protected --
  1522.      * since AppContext is in sun.awt in 1.2, we shouldn't expose it
  1523.      * even indirectly with a public API.
  1524.      */
  1525.     static Hashtable appContextTable = new Hashtable(2);
  1526.  
  1527.     static Object appContextGet(Object key) {
  1528.         
  1529.         return sun.awt.AppContext.getAppContext().get(key);
  1530.         
  1531.  
  1532.  
  1533.  
  1534.  
  1535.     }
  1536.  
  1537.     static void appContextPut(Object key, Object value) {
  1538.         
  1539.         sun.awt.AppContext.getAppContext().put(key, value);
  1540.         
  1541.  
  1542.  
  1543.  
  1544.  
  1545.     }
  1546.  
  1547.     static void appContextRemove(Object key) {
  1548.         
  1549.         sun.awt.AppContext.getAppContext().remove(key);
  1550.         
  1551.  
  1552.  
  1553.  
  1554.  
  1555.     }
  1556.  
  1557.  
  1558.     final static void doPrivileged(final Runnable doRun) {
  1559.       
  1560.         java.security.AccessController.doPrivileged(
  1561.             new java.security.PrivilegedAction() {
  1562.                 public Object run() {
  1563.                   doRun.run();
  1564.                   return null;
  1565.                 }
  1566.             }
  1567.         );
  1568.         
  1569.  
  1570.  
  1571.  
  1572.  
  1573.  
  1574.  
  1575.  
  1576.  
  1577.  
  1578.  
  1579.  
  1580.     }
  1581.  
  1582.     private SwingUtilities() {
  1583.         throw new Error("SwingUtilities is just a container for static methods");
  1584.     }
  1585. }
  1586.